package com.evil.application.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.map.MapUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.evil.account.api.RemoteDepartmentService;
import com.evil.account.api.RemoteUserEnterpriseService;
import com.evil.account.api.RemoteUserService;
import com.evil.application.api.RemoteApplicationOrderDataService;
import com.evil.application.convert.DataConvert;
import com.evil.application.enums.form.control.ControlCodeEnum;
import com.evil.application.enums.order.OrderSpecialControlEnum;
import com.evil.application.mapper.*;
import com.evil.application.pojo.dto.form.control.code.ControlDTO;
import com.evil.application.pojo.dto.form.control.code.DeptSelControlDTO;
import com.evil.application.pojo.dto.form.control.code.MemberSelControlDTO;
import com.evil.application.pojo.dto.form.control.code.SelectControlDTO;
import com.evil.application.pojo.dto.form.control.code.config.ControlSelectConfigDTO;
import com.evil.application.pojo.dto.form.control.option.FormOptionRespDTO;
import com.evil.application.pojo.dto.form.control.option.OrderSelectOptionRespDTO;
import com.evil.application.pojo.dto.order.InitControlDataRespDTO;
import com.evil.application.pojo.dto.permission.control.ControlPermissionDTO;
import com.evil.application.pojo.dto.reporting.data.RefreshAppOrderReqDTO;
import com.evil.application.pojo.entity.*;
import com.evil.application.service.*;
import com.evil.application.util.ApplicationUtil;
import com.evil.application.util.OrderDataUtil;
import com.evil.application.util.RobotUtil;
import com.evil.common.account.dto.department.DepartmentBaseRespDTO;
import com.evil.common.account.dto.department.DepartmentBasesReqDTO;
import com.evil.common.account.dto.user.FindUserIdsByIdReqDTO;
import com.evil.common.account.dto.user.UserBaseRespDTO;
import com.evil.common.account.util.LoginUtil;
import com.evil.common.application.dto.form.SpecialControlConfigDTO;
import com.evil.common.application.dto.order.data.ControlDataDTO;
import com.evil.common.application.dto.order.data.ControlDataValueDTO;
import com.evil.common.application.dto.order.data.SpecialControlData;
import com.evil.common.application.dto.permission.app.AppPermissionDTO;
import com.evil.common.application.enums.ApplicationVersionEnum;
import com.evil.common.application.enums.permission.ApplicationPermissionTypeEnum;
import com.evil.common.application.enums.permission.ControlVisibleEnum;
import com.evil.common.application.enums.permission.PermissionStatusEnum;
import com.evil.common.application.util.ApplicationRedisKeyUtil;
import com.evil.common.core.entity.PageModel;
import com.evil.common.core.enums.BaseEnum;
import com.evil.common.core.exception.BusinessException;
import com.evil.common.core.util.ClassifyUtil;
import com.evil.common.core.util.StreamUtil;
import com.evil.common.es.dto.application.order.ESOrderDataDTO;
import com.evil.common.es.dto.application.order.node.ESNodeHandlerDTO;
import com.evil.common.family.enums.RCodeEnum;
import com.evil.common.core.enums.SwitchEnum;
import com.evil.common.log.annotation.ExecuteTime;
import com.evil.common.log.function.ExecuteTimeFunction;
import com.evil.common.redis.constant.RedisConstant;
import com.evil.common.redis.util.RedisUtil;
import com.github.pagehelper.PageInfo;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RestController;

import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collectors;

/**
 * 应用订单数据表
 *
 * @author liyang
 * @date 2022-08-08 00:00
 */
@Slf4j
@RestController
@AllArgsConstructor
public class ApplicationOrderDataServiceImpl extends ServiceImpl<ApplicationOrderDataMapper, ApplicationOrderData>
        implements ApplicationOrderDataService, RemoteApplicationOrderDataService {

    private final LoginUtil loginUtil;

    private final RedisUtil redisUtil;

    private final RobotUtil robotUtil;

    private final ApplicationInfoMapper applicationInfoMapper;

    private final ApplicationFormMapper applicationFormMapper;

    private final ApplicationFormControlMapper applicationFormControlMapper;

    private final FormControlOptionMapper formControlOptionMapper;

    private final ApplicationProcessNodeMapper applicationProcessNodeMapper;

    private final ApplicationOrderMapper applicationOrderMapper;

    private final ApplicationFormControlService applicationFormControlService;

    private final ApplicationProcessNodeService applicationProcessNodeService;

    private final ControlPermissionService controlPermissionService;

    private final ApplicationPermissionService applicationPermissionService;

    private final ApplicationOrderNodeHandlerService applicationOrderNodeHandlerService;

    private final ElasticsearchService elasticsearchService;

    private final RemoteUserService remoteUserService;

    private final RemoteDepartmentService remoteDepartmentService;

    private final RemoteUserEnterpriseService remoteUserEnterpriseService;

    private final ApplicationLogServiceImpl applicationLogService;

    // region es

    /**
     * 重建ES索引
     */
    @Override
    public void reCreateESIndex() {
        // 总后台登录
        loginUtil.checkPlatform(loginUtil.getTokenInfo().getPlatformType());
        // 检查企业管理员
        remoteUserEnterpriseService.checkEnterpriseManager(loginUtil.getLoginUserEnterprise());

        elasticsearchService.createIndex();
    }

    /**
     * 删除ES索引
     */
    @Override
    public void deleteESIndex() {
        // 总后台登录
        loginUtil.checkPlatform(loginUtil.getTokenInfo().getPlatformType());
        // 检查企业管理员
        remoteUserEnterpriseService.checkEnterpriseManager(loginUtil.getLoginUserEnterprise());

        elasticsearchService.deleteIndex();
    }

    /**
     * 刷新ES订单
     *
     * @param orderId orderId
     */
    @Override
    public void refreshEsOrderId(Long orderId) {
        ApplicationOrder order = applicationOrderMapper.findById(orderId);
        ApplicationInfo app = applicationInfoMapper.findById(order.getApplicationId());
        List<ControlDataDTO> controlDataList = this.getOrderControlData(orderId);
        List<ApplicationOrderNodeHandler> orderNodeHandlers = applicationOrderNodeHandlerService.orderNodeHandlers(order);
        List<ESNodeHandlerDTO> esNodeHandlerDTOS = elasticsearchService.initESNodeHandler(orderNodeHandlers);

        elasticsearchService.save(app, order, controlDataList, esNodeHandlerDTOS);
    }

    /**
     * 刷新搜索引擎
     *
     * @param orderIds orderIds
     */
    @Override
    public void refreshEsOrderIds(Collection<Long> orderIds) {

    }

    /**
     * 刷新ES订单
     *
     * @param refreshAppOrderReqDTO refreshAppOrderReqDTO
     */
    @Override
    public void refreshEsOrderIds(RefreshAppOrderReqDTO refreshAppOrderReqDTO) {
        ExecuteTimeFunction start = ExecuteTimeFunction.start();
        // 订单列表
        PageModel<Long> pageModel;
        Supplier<PageInfo<ApplicationOrder>> query;
        DataConvert dataConvert = new DataConvert(loginUtil)
                .initAppMap();
        if (Objects.nonNull(refreshAppOrderReqDTO.getEnterpriseId())) {
            // 校验权限
            loginUtil.checkEnterpriseId(refreshAppOrderReqDTO.getEnterpriseId());
            pageModel = new PageModel<>(1, 100, refreshAppOrderReqDTO.getEnterpriseId());
            query = () -> applicationOrderMapper.findPageByEnterpriseId(pageModel);
        } else {
            ApplicationInfo applicationInfo;
            if (Objects.nonNull(refreshAppOrderReqDTO.getApplicationId())) {
                applicationInfo = dataConvert.getAppById(refreshAppOrderReqDTO.getApplicationId());
            } else if (Objects.nonNull(refreshAppOrderReqDTO.getApplicationKey())) {
                applicationInfo = dataConvert.getAppByKey(refreshAppOrderReqDTO.getApplicationKey());
            } else {
                // 至少一个参数
                throw new BusinessException(BaseEnum.ERROR_PARAMETER);
            }
            // 校验权限
            loginUtil.checkEnterpriseId(applicationInfo.getEnterpriseId());
            pageModel = new PageModel<>(1, 100, applicationInfo.getApplicationId());
            query = () -> applicationOrderMapper.findPageByAppId(pageModel);
        }

        // 先删除
        start.reset();
        elasticsearchService.delete(refreshAppOrderReqDTO);
        start.log("【刷新搜索引擎】，先删除");

        while (true) {
            PageInfo<ApplicationOrder> page = query.get();
            log.info("【刷新搜索引擎】，查询数据，第{}页，总页数：{}，总条数：{}：", page.getPageNum(), page.getPages(), page.getTotal());
            List<ApplicationOrder> orders = page.getList();
            if (orders.isEmpty()) {
                break;
            }

            // 获取订单应用
            start.reset();
            dataConvert.getAppByIds(StreamUtil.transListT(orders, ApplicationOrder::getApplicationId), true);
            start.log("【刷新搜索引擎】，获取订单应用");
            // 获取订单数据
            start.reset();
            Map<Long, List<ControlDataDTO>> ordersDataMap = this.orderListData(orders, false, true);
            start.log("【刷新搜索引擎】，获取订单数据");
            // 获取订单节点处理人
            start.reset();
            Map<Long, List<ESNodeHandlerDTO>> orderNodeHandlersMap = StreamUtil.transMapV(
                    applicationOrderNodeHandlerService.findMapByOrderIds(ordersDataMap.keySet()), elasticsearchService::initESNodeHandler);
            start.log("【刷新搜索引擎】，获取订单节点处理人");

            // 转换ES数据格式
            start.reset();
            List<ESOrderDataDTO> esOrders = orders.stream().map(order -> {
                ApplicationInfo app = dataConvert.getAppById(order.getApplicationId());
                List<ControlDataDTO> controlDataList = ordersDataMap.getOrDefault(order.getOrderId(), new ArrayList<>());
                List<ESNodeHandlerDTO> nodeHandlers = orderNodeHandlersMap.getOrDefault(order.getOrderId(), new ArrayList<>());
                return elasticsearchService.initESOrder(app, order, controlDataList, nodeHandlers);
            }).collect(Collectors.toList());
            start.log("【刷新搜索引擎】，转换ES数据格式");

            // 推送数据
            start.reset();
            elasticsearchService.saveBatch(esOrders);
            start.log("【刷新搜索引擎】，推送数据");

            if (!page.isHasNextPage()) {
                break;
            } else {
                pageModel.setPageNum(pageModel.getPageNum() + 1);
            }
        }
        log.info("【刷新搜索引擎批处理】，操作成功");
    }
    // endregion

    /**
     * 获取订单数据转换工具
     *
     * @return DataConvert
     */
    @Override
    public DataConvert getDataConvert() {
        return this.getDataConvert(loginUtil.getLoginEnterpriseId(), loginUtil.getLoginUserId());
    }

    /**
     * 初始化应用订单数据（机器人创建订单）
     *
     * @param applicationId applicationId
     * @return InitControlDataDTO
     */
    @Override
    public InitControlDataRespDTO initAppOrderData(Long applicationId) {
        // 应用
        ExecuteTimeFunction start = ExecuteTimeFunction.start();
        ApplicationInfo applicationInfo = applicationInfoMapper.findById(applicationId);
        start.log("【初始化应用订单数据（机器人创建订单）- 获取应用】");
        // 应用表单控件 数据
        start.reset();
        List<ControlDTO> controls = applicationFormControlService.appReleaseControlDTOs_Cache(applicationInfo);
        start.log("【初始化应用订单数据（机器人创建订单）- 应用表单控件】");
        // 层级分类 （###不需要覆盖返回值）
        ApplicationUtil.classifyControl(controls);

        List<Long> controlIds = new ArrayList<>();
        Map<Long, ControlDTO> controlMap = new HashMap<>();
        Map<Long, ControlDataDTO> controlDataMap = new HashMap<>();
        controls.forEach(control -> {
            controlIds.add(control.getControlId());
            controlMap.put(control.getControlId(), control);
            controlDataMap.put(control.getControlId(), ApplicationUtil.controlToControlData(control));
        });
        start.reset();
        Map<Long, List<FormOptionRespDTO>> controlOptionsMap = formControlOptionMapper.findGroupBasesMapByControlIds(controlIds, true);
        start.log("【初始化应用订单数据（机器人创建订单）- 获取控件选项】");

        InitControlDataRespDTO initControlDataRespDTO = new InitControlDataRespDTO();
        initControlDataRespDTO.setApplicationKey(applicationInfo.getApplicationKey());
        initControlDataRespDTO.setControlDataMap(controlDataMap);
        initControlDataRespDTO.setControlMap(controlMap);
        initControlDataRespDTO.setControlOptionsMap(controlOptionsMap);
        return initControlDataRespDTO;
    }

    /**
     * 关联控件数据
     *
     * @param orderDataId orderDataId
     * @param dataConvert 订单数据转换 处理缓存
     * @return FormOptionRespDTO
     */
    @Override
    public FormOptionRespDTO orderRelatedSelect(Long orderDataId, DataConvert dataConvert) {
        ApplicationOrderData orderData = this.baseMapper.findById(orderDataId);
        return this.orderDataToFormOption(orderData, dataConvert);
    }

    /**
     * 关联控件数据列表
     *
     * @param orderDataIds orderDataIds
     * @return List
     */
    @Override
    public List<FormOptionRespDTO> orderRelatedSelect(Collection<Long> orderDataIds) {
        DataConvert dataConvert = new DataConvert(loginUtil)
                .initUserMap()
                .initDepartmentMap()
                .initFileMap()
                .initControlMap()
                .initOptionMap();
        return this.orderRelatedSelect(orderDataIds, dataConvert);
    }

    /**
     * 关联控件数据Map
     *
     * @param orderDataIds orderDataIds
     * @return Map<orderDataId, FormOptionRespDTO>
     */
    @Override
    public Map<Long, FormOptionRespDTO> orderRelatedSelectMap(Collection<Long> orderDataIds) {
        DataConvert dataConvert = new DataConvert(loginUtil)
                .initUserMap()
                .initDepartmentMap()
                .initFileMap()
                .initControlMap()
                .initOptionMap();
        return this.orderRelatedSelectMap(orderDataIds, dataConvert);
    }

    /**
     * 关联控件数据列表
     *
     * @param orderDataIds orderDataIds
     * @param dataConvert  dataConvert
     * @return List
     */
    @Override
    public List<FormOptionRespDTO> orderRelatedSelect(Collection<Long> orderDataIds, DataConvert dataConvert) {
        return this.orderDataToFormOption(this.baseMapper.findByIds(orderDataIds, false), dataConvert);
    }

    /**
     * 关联控件数据Map
     *
     * @param orderDataIds orderDataIds
     * @param dataConvert  dataConvert
     * @return Map<orderDataId, FormOptionRespDTO>
     */
    @Override
    public Map<Long, FormOptionRespDTO> orderRelatedSelectMap(Collection<Long> orderDataIds, DataConvert dataConvert) {
        return StreamUtil.toMapK(this.orderRelatedSelect(orderDataIds), FormOptionRespDTO::getOptionId);
    }

    /**
     * 获取订单数据
     *
     * @param orderId orderId
     * @return ApplicationOrderData 列表
     */
    @Override
    public List<ApplicationOrderData> orderDataList(Long orderId) {
        return this.baseMapper.findByOrderId(orderId);
    }

    /**
     * 获取订单数据
     *
     * @param orderIds orderIds
     * @return ApplicationOrderData 列表
     */
    @Override
    public List<ApplicationOrderData> ordersDataList(Collection<Long> orderIds, boolean filterDeleted) {
        return this.baseMapper.findByOrderIds(orderIds, filterDeleted);
    }

    /**
     * 订单数据
     *
     * @param orderId orderId
     * @return List
     */
    @Override
    public List<ControlDataDTO> getOrderControlData(Long orderId) {
        return this.getOrderControlData(applicationOrderMapper.findById(orderId));
    }

    /**
     * 获取订单指定节点数据
     *
     * @param applicationOrder applicationOrder
     * @return List
     */
    @Override
    public List<ControlDataDTO> getOrderControlData(ApplicationOrder applicationOrder) {
        List<ControlDTO> controlDTOS = applicationFormControlService.appReleaseControlDTOs_Cache(applicationOrder.getApplicationId());
        // 转订单控件数据
        List<ControlDataDTO> controlDataList = ApplicationUtil.controlDTOsToControlData(controlDTOS);
        // 订单数据map
        HashMap<Long, List<ControlDataDTO>> orderDataListMap = MapUtil.of(applicationOrder.getOrderId(), controlDataList);
        // 订单数据
        List<ApplicationOrderData> orderDataList = this.baseMapper.findByOrderId(applicationOrder.getOrderId());
        // 订单Map
        Map<Long, ApplicationOrder> orderMap = MapUtil.of(applicationOrder.getOrderId(), applicationOrder, true);
        // 订单数据列表Map
        DataConvert dataConvert = this.getDataConvert(applicationOrder.getEnterpriseId(), null);
        return this.handleOrderDataToDTO(orderMap, orderDataList, orderDataListMap, dataConvert, false, true)
                .getOrDefault(applicationOrder.getOrderId(), new ArrayList<>());
    }

    /**
     * 获取订单指定节点数据
     *
     * @param applicationOrder applicationOrder
     * @param processNode      processNode
     * @param perfect          是否完善数据详细信息
     * @return List
     */
    @Override
    public List<ControlDataDTO> getOrderControlData(ApplicationOrder applicationOrder, ApplicationProcessNode processNode, boolean perfect) {
        // 订单数据
        List<ApplicationOrderData> orderDataList = this.baseMapper.findByOrderId(applicationOrder.getOrderId());
        return this.getOrderControlData(applicationOrder, orderDataList, processNode, perfect);
    }

    /**
     * 转换订单数据
     *
     * @param order         order
     * @param orderDataList orderDataList
     * @param node          node
     * @param perfect       perfect
     * @return List
     */
    @Override
    public List<ControlDataDTO> getOrderControlData(ApplicationOrder order, List<ApplicationOrderData> orderDataList, ApplicationProcessNode node, boolean perfect) {
        Long orderId = order.getOrderId();
        // 是否指定节点/否则获取全部数据
        LinkedHashMap<Long, Long> orderNodeIdMap = null;
        boolean filter = null != node;
        if (filter) {
            // 获取节点
            orderNodeIdMap = new LinkedHashMap<>();
            orderNodeIdMap.put(orderId, node.getNodeId());
        }
        // 订单Map
        Map<Long, ApplicationOrder> orderMap = MapUtil.of(order.getOrderId(), order, true);
        // 订单可见控件列表Map
        Map<Long, List<ControlDataDTO>> orderDataControlDataListMap = this.getOrderControlDataListMap(orderMap, orderNodeIdMap, orderDataList);
        // 订单数据列表Map
        Map<Long, List<ControlDataDTO>> ordersDataListMap = this.handleOrderDataToDTO(
                orderMap, orderDataList, orderDataControlDataListMap, this.getDataConvert(), filter, perfect);

        return ordersDataListMap.getOrDefault(order.getOrderId(), new ArrayList<>());
    }

    /**
     * 订单列表 数据列表
     *
     * @param orders                orders
     * @param filterNodeVisibleData filterNodeVisibleData
     * @param perfect               是否完善数据详细信息
     * @return OrdersControlDataDTO
     */
    @Override
    public Map<Long, List<ControlDataDTO>> orderListData(Collection<ApplicationOrder> orders, boolean filterNodeVisibleData, boolean perfect) {
        Set<Long> orderIds = StreamUtil.transSetT(orders, ApplicationOrder::getOrderId);
        List<ApplicationOrderData> ordersDataList = this.baseMapper.findByOrderIds(orderIds, true);
        return this.orderListData(orders, ordersDataList, filterNodeVisibleData, perfect);
    }

    /**
     * 订单列表 数据列表
     *
     * @param orders                orders
     * @param ordersDataList        ordersDataList
     * @param filterNodeVisibleData filterNodeVisibleData
     * @param perfect               是否完善数据详细信息
     * @return OrdersControlDataDTO
     */
    @Override
    public Map<Long, List<ControlDataDTO>> orderListData(Collection<ApplicationOrder> orders, List<ApplicationOrderData> ordersDataList, boolean filterNodeVisibleData, boolean perfect) {
        // 订单map
        Map<Long, ApplicationOrder> orderMap = StreamUtil.toMapK(orders, ApplicationOrder::getOrderId);
        // 是否过滤节点数据
        LinkedHashMap<Long, Long> orderNodeIdMap = filterNodeVisibleData ? new LinkedHashMap<>() : null;
        // 订单可见控件列表Map
        Map<Long, List<ControlDataDTO>> orderDataControlDataListMap = this.getOrderControlDataListMap(orderMap, orderNodeIdMap, ordersDataList);
        // 订单数据列表Map
        return this.handleOrderDataToDTO(orderMap, ordersDataList, orderDataControlDataListMap, this.getDataConvert(), filterNodeVisibleData, perfect);
    }

    /**
     * 校验订单数据，通过时保存，并且重新获取最新数据
     *
     * @param app    app
     * @param form   form
     * @param order  order
     * @param data   data
     * @param nodeId nodeId
     * @return 重新获取最新数据
     */
    @Override
    public List<ControlDataDTO> checkAndSave(ApplicationInfo app, ApplicationForm form, ApplicationOrder order, List<ControlDataDTO> data, Long nodeId) {
        // 获取订单数据
        List<ApplicationOrderData> orderDataList = this.orderDataList(order.getOrderId());
        // 完善订单数据
        List<ControlDataDTO> oldData = this.getOrderControlData(order, orderDataList, null, true);
        // 验证表单数据
        this.verifyOrderDataList(app, oldData, data, nodeId);

        // 机器人
        robotUtil.before(app.getApplicationKey(), order, data, oldData);
        // 保存订单
        applicationLogService.saveAndCheck(applicationOrderMapper, ApplicationOrder::getOrderId, order);
        // 处理并保存表单数据
        this.handleAndSave(app, form, order, orderDataList, data, false);
        // 重新获取订单数据
        return this.getOrderControlData(order, null, true);
    }

    /**
     * 验证表单数据
     *
     * @param app     applicationInfo
     * @param oldData oldData
     * @param data    data
     * @param nodeId  nodeId
     */
    @Override
    public void verifyOrderDataList(ApplicationInfo app, List<ControlDataDTO> oldData, List<ControlDataDTO> data, Long nodeId) {
        // 获取表单控件列表
        List<ControlDTO> controls = applicationFormControlService.appReleaseControlDTOs_Cache(app);

        // 过滤节点可见控件
        Map<Long, ControlPermissionDTO> controlPermissionMap = new HashMap<>();
        if (null != nodeId) {
            List<Long> visibleControlIds = new ArrayList<>();
            // 获取节点控件配置
            Set<Long> controlIds = controls.stream().map(ControlDTO::getControlId).collect(Collectors.toSet());
            controlPermissionService.nodeControlPermissions(nodeId, controlIds).forEach(controlPermission -> {
                controlPermissionMap.put(controlPermission.getControlId(), controlPermission);
                if (ControlVisibleEnum.INVISIBLE.getId() != controlPermission.getVisible()) {
                    visibleControlIds.add(controlPermission.getControlId());
                }
            });
            // 过滤
            controls = controls.stream().filter(e -> visibleControlIds.contains(e.getControlId())).collect(Collectors.toList());
        }

        Map<Long, ControlDataDTO> dataMap = StreamUtil.toMapK(oldData, ControlDataDTO::getControlId);
        Map<Long, ControlDTO> controlMap = StreamUtil.toMapK(controls, ControlDTO::getControlId);

        Function<ControlDataDTO, ControlPermissionDTO> getControlPermission = c
                -> controlPermissionMap.getOrDefault(c.getControlId(), new ControlPermissionDTO(c.getControlId()));

        List<Long> specialControlIds = OrderSpecialControlEnum.getSpecialControlIds();
        data.forEach(controlDataDTO -> {
            // 特殊控件不需要校验
            if (!specialControlIds.contains(controlDataDTO.getControlId())) {
                ControlPermissionDTO controlPermission = getControlPermission.apply(controlDataDTO);
                // 验证表单数据
                this.verifyOrderData(dataMap.get(controlDataDTO.getControlId()), controlDataDTO, controlPermission, controlMap);
                // 表格
                if (ControlCodeEnum.TABLE.getCode().equals(controlDataDTO.getControlCode())) {
                    controlDataDTO.getTableValues().forEach(row -> row.forEach(tableControlData -> {
                        // 表格 没有新增权限
                        if (!SwitchEnum.isOpen(controlPermission.getAddStatus())) {
                            if (Objects.isNull(tableControlData.getOrderDataId())) {
                                throw new BusinessException(RCodeEnum.ERROR_UNAUTHORIZED, this.getUnauthorizedMsg(tableControlData.getControlTitle(), "新增"));
                            }
                        }
                        // 表格 没有删除权限
                        if (!SwitchEnum.isOpen(controlPermission.getDeleteStatus())) {
                            if (dataMap.containsKey(controlDataDTO.getControlId())) {
                                ControlDataDTO tableData = dataMap.get(controlDataDTO.getControlId());
                                if (tableData.getTableValues().size() != controlDataDTO.getTableValues().size()) {
                                    throw new BusinessException(RCodeEnum.ERROR_UNAUTHORIZED, this.getUnauthorizedMsg(tableControlData.getControlTitle(), "删除"));
                                }
                            }
                        }
                        ControlPermissionDTO tableControlPermission = getControlPermission.apply(tableControlData);
                        // 验证表单数据
                        this.verifyOrderData(dataMap.get(controlDataDTO.getControlId()), tableControlData, tableControlPermission, controlMap);
                    }));
                }
            }
        });
    }

    /**
     * 处理并保存表单数据
     *
     * @param app      app
     * @param form     form
     * @param order    order
     * @param data     data
     * @param isCreate 是否为创建
     */
    @Override
    @ExecuteTime(name = "【handleAndSave】")
    public void handleAndSave(ApplicationInfo app, ApplicationForm form, ApplicationOrder order, Collection<ControlDataDTO> data, boolean isCreate) {
        ExecuteTimeFunction start = ExecuteTimeFunction.start();
        List<ApplicationOrderData> modifies = this.handle(app, form, order, data, isCreate);
        start.log("【处理表单数据】");
        // 保存数据
        start.reset();
        this.save(modifies);
        start.log("【保存表单数据】");
        // 编辑订单ID 记录到线程
        redisUtil.sSetAndTime(ApplicationRedisKeyUtil.requestUuidRobotModifyOrderId(),
                RedisConstant.REQUEST_UUID_EXPIRE_IN_SECOND, order.getOrderId());
    }

    /**
     * 处理并保存表单数据
     *
     * @param app           app
     * @param form          form
     * @param order         order
     * @param orderDataList orderDataList
     * @param data          data
     * @param isCreate      是否为创建
     */
    @Override
    public void handleAndSave(ApplicationInfo app, ApplicationForm form, ApplicationOrder order, List<ApplicationOrderData> orderDataList, Collection<ControlDataDTO> data, boolean isCreate) {
        ExecuteTimeFunction start = ExecuteTimeFunction.start();
        List<ApplicationOrderData> modifies = this.handle(app, form, order, orderDataList, data, isCreate);
        start.log("【处理表单数据】");
        // 保存数据
        start.reset();
        this.save(modifies);
        start.log("【保存表单数据】");
        // 编辑订单ID 记录到线程
        redisUtil.sSetAndTime(ApplicationRedisKeyUtil.requestUuidRobotModifyOrderId(),
                RedisConstant.REQUEST_UUID_EXPIRE_IN_SECOND, order.getOrderId());
    }

    /**
     * 处理表单数据
     *
     * @param app      app
     * @param form     form
     * @param order    order
     * @param data     data
     * @param isCreate 是否为创建
     */
    @Override
    public List<ApplicationOrderData> handle(ApplicationInfo app, ApplicationForm form, ApplicationOrder order, Collection<ControlDataDTO> data, boolean isCreate) {
        // 获取订单数据
        ExecuteTimeFunction start = ExecuteTimeFunction.start();
        List<ApplicationOrderData> orderDataList = new ArrayList<>();
        if (!isCreate) {
            orderDataList.addAll(this.baseMapper.findByOrderId(order.getOrderId()));
        }
        start.log("【处理表单数据 - 获取订单数据】");
        return this.handle(app, form, order, orderDataList, data, isCreate);
    }

    /**
     * 处理表单数据
     *
     * @param app           app
     * @param form          form
     * @param order         order
     * @param orderDataList orderDataList
     * @param data          data
     * @param isCreate      是否为创建
     * @return List
     */
    @Override
    public List<ApplicationOrderData> handle(ApplicationInfo app, ApplicationForm form, ApplicationOrder order, List<ApplicationOrderData> orderDataList, Collection<ControlDataDTO> data, boolean isCreate) {
        UserBaseRespDTO loginUser = loginUtil.getLoginUserBase();
        order.setModifierId(loginUser.getUserId());
        order.setModifierName(loginUser.getNickName());
        order.setUpdated(new Date());

        // 防止控件数据错误
        ExecuteTimeFunction start = ExecuteTimeFunction.start();
        Map<Long, ControlDTO> controlMap = applicationFormControlService.appReleaseControlDTOMap_Cache(app);
        start.log("【处理表单数据 - 获取表单控件】");

        // 处理特殊控件数据
        start.reset();
        this.handleSpecial(form, order, data, isCreate);
        start.log("【处理表单数据 - 处理特殊控件数据】");

        // 表格行 数据map
        Map<Long, Map<Integer, List<ApplicationOrderData>>> tableRowDataListMap = StreamUtil.groupFAndThenGroup(
                orderDataList,
                e -> !ApplicationUtil.DEFAULT_PARENT_CONTROL_ID.equals(e.getParentControlId()),
                ApplicationOrderData::getParentControlId,
                ApplicationOrderData::getSort);

        // 完善数据
        Map<Long, ApplicationOrderData> dataMap = StreamUtil.toMapK(orderDataList, ApplicationOrderData::getOrderDataId);
        Consumer<ControlDataDTO> prefect = c -> {
            if (!controlMap.containsKey(c.getControlId())) {
                throw new BusinessException(RCodeEnum.APPLICATION_FORM_CONTROL_NOT_EXIST);
            }
            ControlDTO control = controlMap.get(c.getControlId());
            c.setControlCode(control.getControlCode());
            c.setParentControlId(control.getParentControlId());

            // 特殊控件补充数据id
            OrderSpecialControlEnum.isExistById(c.getControlId())
                    .map(em -> dataMap.get(em.getId()))
                    .ifPresent(d -> c.setOrderDataId(d.getOrderDataId()));
        };

        // 处理数据 (新增/修改)
        start.reset();
        List<ApplicationOrderData> modifies = new ArrayList<>();
        // 过滤重复数据
        Set<Long> orderDataIds = new HashSet<>();
        for (ControlDataDTO controlData : data) {
            // 过滤已删除控件
            if (!controlMap.containsKey(controlData.getControlId())) {
                continue;
            }
            ControlDTO controlDTO = controlMap.get(controlData.getControlId());
            // 如果上级控件是表格，则当前层级遍历跳过
            if (ApplicationUtil.meaningful(controlDTO.getParentControlId()) && controlMap.containsKey(controlDTO.getParentControlId())) {
                ControlDTO parentControl = controlMap.get(controlDTO.getParentControlId());
                if (ControlCodeEnum.TABLE.getCode().equals(parentControl.getControlCode())) {
                    continue;
                }
            }
            // 过滤重复的订单数据
            if (Objects.nonNull(controlData.getOrderDataId()) && !orderDataIds.add(controlData.getOrderDataId())) {
                continue;
            }
            // 防止控件数据错误
            prefect.accept(controlData);
            // 处理数据
            this.initOrderData(modifies, order, dataMap, controlData, ApplicationUtil.DEFAULT_ORDER_DATA_SORT, false);
            // 处理数据-表格
            if (ControlCodeEnum.TABLE.getCode().equals(controlData.getControlCode())) {
                // 表格DB数据
                Map<Integer, List<ApplicationOrderData>> dbRowDataMap = tableRowDataListMap.getOrDefault(controlData.getControlId(), new HashMap<>());
                // 记录没有被删除的表格行号
                Set<Integer> rows = new HashSet<>();
                // 行号自增
                AtomicInteger atomicInteger = new AtomicInteger();
                controlData.getTableValues().forEach(tableValues -> {
                    // 行号自增
                    int sort = atomicInteger.getAndIncrement();
                    tableValues.forEach(tableValue -> {
                        // 防止控件数据错误
                        prefect.accept(controlData);

                        // 记录没有被删除的表格行号
                        if (Objects.nonNull(tableValue.getOrderDataId())) {
                            if (!dataMap.containsKey(tableValue.getOrderDataId())) {
                                throw new BusinessException(RCodeEnum.APPLICATION_ORDER_DATA_NOT_EXIST);
                            }
                            // 过滤重复数据
                            orderDataIds.add(tableValue.getOrderDataId());
                            ApplicationOrderData orderData = dataMap.get(tableValue.getOrderDataId());
                            rows.add(orderData.getSort());
                        }
                        // 处理数据 （表格数据都更新）
                        this.initOrderData(modifies, order, dataMap, tableValue, sort, true);
                    });
                });

                // 删除表格无用行
                dbRowDataMap.forEach((sort, dataList) -> {
                    if (!rows.contains(sort)) {
                        // 已被删除的
                        modifies.addAll(dataList.stream()
                                .peek(e -> e.setIsDeleted(SwitchEnum.YES.getId()))
                                .toList());
                    }
                });
            }
        }
        start.log("【处理表单数据 - 新增/修改】");

        // 删除无效数据
        start.reset();
        orderDataIds.clear();
        Set<Long> controlIds = new HashSet<>();
        modifies.forEach(e -> {
            orderDataIds.add(e.getOrderDataId());
            controlIds.add(e.getControlId());
        });
        // 当前有修改的控件 但是却失效了
        Predicate<ApplicationOrderData> filterVoid = o -> controlIds.contains(o.getControlId()) && !orderDataIds.contains(o.getOrderDataId());
        modifies.addAll(StreamUtil.peekF(orderDataList, filterVoid, o -> o.setIsDeleted(SwitchEnum.YES.getId())));
        start.log("【处理表单数据 - 删除无效数据】");

        return modifies;
    }

    /**
     * 修改订单节点处理人数据
     *
     * @param order      order
     * @param nodeHandle nodeHandle
     */
    @Override
    public void modifyOrderNodeData(ApplicationOrder order, Consumer<ApplicationOrderData> nodeHandle) {
        applicationLogService.saveAndCheck(applicationOrderMapper, ApplicationOrder::getOrderId, order);
        // 获取订单节点控件数据、更新人控件数据、更新时间控件数据
        List<Long> controlIds = Arrays.asList(
                OrderSpecialControlEnum.NODE.getId(),
                OrderSpecialControlEnum.MODIFIER.getId(),
                OrderSpecialControlEnum.UPDATE.getId()
        );
        Map<Long, ControlDataDTO> controlDataMap = new HashMap<>();
        // 更新订单节点控件数据
        DataConvert dataConvert = this.getDataConvert();
        this.baseMapper.controlFirstDataMap(order.getOrderId(), controlIds).forEach((controlId, orderData) -> {
            OrderSpecialControlEnum em = OrderSpecialControlEnum.findById(controlId);
            // 节点
            if (OrderSpecialControlEnum.NODE == em) {
                nodeHandle.accept(orderData);
            } else {
                SpecialControlData specialControlData = BeanUtil.copyProperties(order, SpecialControlData.class);
                orderData.setOrderData(JSON.toJSONString(em.getClassifier().apply(specialControlData, remoteUserService::findBaseById)));
            }
            applicationLogService.saveAndCheck(this.baseMapper, ApplicationOrderData::getOrderDataId, orderData);

            ControlDataDTO controlDataDTO = dataConvert.initOrderData(order, orderData, true, false);
            controlDataMap.put(controlDataDTO.getControlId(), controlDataDTO);
        });
        ESOrderDataDTO esOrder = elasticsearchService.esOrder(order.getOrderId());
        esOrder.setUpdated(order.getUpdated());
        // 订单节点处理人
        List<ApplicationOrderNodeHandler> nodeHandlers = applicationOrderNodeHandlerService.orderNodeHandlers(order);
        esOrder.setNodeHandlers(elasticsearchService.initESNodeHandler(nodeHandlers));
        // 局部更新订单数据
        elasticsearchService.save(esOrder, controlDataMap);
    }

    /**
     * 保存订单数据
     *
     * @param orderDataList orderDataList
     */
    @Override
    public void save(List<ApplicationOrderData> orderDataList) {
        applicationLogService.saveBatchAndCheck(this.baseMapper, ApplicationOrderData::getOrderDataId, orderDataList);
    }

    /**
     * 获取订单 可见控件列表
     *
     * @param orderMap       orderMap
     * @param orderNodeIdMap 订单节点idMap 如果有传值，优先级最高；如果为null 则不过滤节点数据
     * @param orderDataList  orderDataList
     * @return Map<orderId, List < ControlDataDTO>>
     */
    private Map<Long, List<ControlDataDTO>> getOrderControlDataListMap(Map<Long, ApplicationOrder> orderMap,
                                                                       LinkedHashMap<Long, Long> orderNodeIdMap,
                                                                       List<ApplicationOrderData> orderDataList) {
        ApplicationVersionEnum versionEnum = ApplicationVersionEnum.RELEASE_VERSION;
        // 订单应用map
        Map<Long, Long> orderAppIdMap = StreamUtil.transMapV(orderMap, ApplicationOrder::getApplicationId);
        // 应用表单
        List<ApplicationForm> forms = applicationFormMapper.findByAppIdsAndVersion(orderAppIdMap.values(), versionEnum.getId());
        Map<Long, ApplicationForm> formMap = StreamUtil.toMapK(forms, ApplicationForm::getFormId);
        Map<Long, ApplicationForm> appFormIdMap = StreamUtil.toMapK(forms, ApplicationForm::getApplicationId);
        // 表单控件
        List<ApplicationFormControl> controls = applicationFormControlMapper.findByFormIds(formMap.keySet());
        Map<Long, ApplicationFormControl> controlMap = StreamUtil.toMapK(controls, ApplicationFormControl::getControlId);
        // 表单控件map
        Map<Long, Set<Long>> formControlIdsMap = StreamUtil.groupAndThenTransSet(controls,
                ApplicationFormControl::getFormId, ApplicationFormControl::getControlId);

        Function<Long, ApplicationForm> getOrderForm = orderId -> {
            Long appId = orderAppIdMap.get(orderId);
            return appFormIdMap.get(appId);
        };

        // 不过滤，直接返回
        if (Objects.isNull(orderNodeIdMap)) {
            return StreamUtil.toMapV(orderMap.keySet(), orderId -> {
                ApplicationForm form = getOrderForm.apply(orderId);
                Set<Long> controlIds = formControlIdsMap.getOrDefault(form.getFormId(), new HashSet<>());
                return this.nodeControlToData(form, controlIds, controlMap);
            });
        }
        // 过滤，执行过滤逻辑
        orderNodeIdMap = new LinkedHashMap<>();
        // 获取所有订单 应用开始节点
        Map<Long, Long> orderStartNodeIdMap = applicationProcessNodeService.findAppStartNodeMap(orderAppIdMap.values(), versionEnum);
        // 获取订单当前节点
        Optional<ApplicationOrderData> nodeOptional = OrderSpecialControlEnum.NODE.findOrderData(orderDataList);
        if (nodeOptional.isPresent()) {
            ApplicationOrderData node = nodeOptional.get();
            List<Long> ids = OrderDataUtil.getControlValueIds(JSON.parseArray(node.getOrderData(), ControlDataValueDTO.class));
            Long nodeId = StreamUtil.isExistFirst(ids, e -> ApplicationUtil.DEFAULT_NODE_ID.compareTo(e) <= 0)
                    .orElseGet(() -> orderStartNodeIdMap.get(node.getOrderId()));
            orderNodeIdMap.put(node.getOrderId(), nodeId);
        }

        // 节点信息 Map
        Set<Long> nodeIds = new HashSet<>(orderStartNodeIdMap.values());
        nodeIds.addAll(StreamUtil.filterSet(orderNodeIdMap.values(), Objects::nonNull));
        Map<Long, ApplicationProcessNode> nodeMap = applicationProcessNodeMapper.findMapByIds(nodeIds, false);

        // 获取订单控件列表方法
        Function<Long, Set<Long>> getOrderControls = orderId -> {
            Long formId = getOrderForm.apply(orderId).getFormId();
            return formControlIdsMap.getOrDefault(formId, new HashSet<>());
        };

        // 获取节点控件ids
        Map<Long, Set<Long>> nodeControlIdsMap = new HashMap<>();
        orderNodeIdMap.forEach((orderId, nodeId) -> {
            Set<Long> nodeControlIds = nodeControlIdsMap.getOrDefault(nodeId, new HashSet<>());
            nodeControlIds.addAll(getOrderControls.apply(orderId));
            nodeControlIdsMap.put(nodeId, nodeControlIds);
        });
        // 获取节点可见控件ids
        Map<Long, List<Long>> nodeVisibleControlIdsMap = controlPermissionService.nodesVisibleControlPermissionMap(orderNodeIdMap.values(), nodeControlIdsMap);

        // 返回订单 控件列表 Map
        return StreamUtil.transMapV_Expand(orderNodeIdMap, (orderId, nodeId) -> {
            // 应用表单
            ApplicationForm form = getOrderForm.apply(orderId);
            // 节点
            ApplicationProcessNode processNode = null;
            if (Objects.nonNull(nodeId)) {
                if (!nodeMap.containsKey(nodeId)) {
                    throw new BusinessException(BaseEnum.RUN_ERROR, "订单数据错误");
                }
                processNode = nodeMap.get(nodeId);
            }
            Collection<Long> controlIds;
            if (Objects.nonNull(processNode)) {
                controlIds = nodeVisibleControlIdsMap.getOrDefault(processNode.getNodeId(), new ArrayList<>());
            } else {
                controlIds = getOrderControls.apply(orderId);
            }
            return this.nodeControlToData(form, controlIds, controlMap);
        });
    }

    /**
     * 订单数据数据
     *
     * @param orderMap              订单map
     * @param orderDataList         订单数据列表
     * @param appControlDataListMap 应用控件数据DTO Map<orderId, List<ControlDataDTO>>
     * @param filterCurrentNode     是否过滤 当前登录人可见节点
     * @param perfect               是否完善数据详细信息
     * @return OrdersControlDataDTO
     */
    private Map<Long, List<ControlDataDTO>> handleOrderDataToDTO(Map<Long, ApplicationOrder> orderMap,
                                                                 List<ApplicationOrderData> orderDataList,
                                                                 Map<Long, List<ControlDataDTO>> appControlDataListMap,
                                                                 DataConvert dataConvert,
                                                                 boolean filterCurrentNode,
                                                                 boolean perfect) {
        // 控件数据列表转有序map
        Function<List<ControlDataDTO>, Map<Long, ControlDataDTO>> dataListToMap = list -> StreamUtil.toOrderlyMapCK(list,
                Comparator.comparingInt(ControlDataDTO::defaultSort), ControlDataDTO::getControlId);

        // 获取订单控件数据map Map<orderId, Map<controlId, DTO>>
        ExecuteTimeFunction start = ExecuteTimeFunction.start();
        Map<Long, Map<Long, ControlDataDTO>> orderControlDataMap = StreamUtil.transMapV(appControlDataListMap, dataListToMap);
        start.log("【初始化订单数据数据】，获取订单控件数据map");

        // 获取订单子级控件数据map Map<orderId, Map<parentControlId, Map<controlId, DTO>>>
        start.reset();
        Map<Long, Map<Long, Map<Long, ControlDataDTO>>> orderControlChildrenDataMap = StreamUtil.transMapV(appControlDataListMap,
                v -> StreamUtil.groupAndThenListToMap(v, ControlDataDTO::getParentControlId, dataListToMap));
        start.log("【初始化订单数据数据】，获取订单子级控件数据map");

        // 过滤有效的控件数据
        start.reset();
        orderDataList = StreamUtil.filter(orderDataList, orderData -> {
            if (!orderControlDataMap.containsKey(orderData.getOrderId())) {
                throw new BusinessException(BaseEnum.RUN_ERROR, "订单数据错误");
            }
            return orderControlDataMap.get(orderData.getOrderId()).containsKey(orderData.getControlId());
        });
        start.log("【初始化订单数据数据】，过滤有效的控件数据");

        // 预先 缓存订单数据需要的 文件、人员、部门、选项、引用
        start.reset();
        dataConvert.cacheOrderData(orderDataList);
        start.log("【初始化订单数据数据】，预先 缓存订单数据需要的 文件、人员、部门、选项、引用");
        // 特殊控件值 或者 有效控件值
        Predicate<ApplicationOrderData> notVoid = od -> OrderSpecialControlEnum.isSpecialControlId(od.getControlId()) || Objects.nonNull(dataConvert.getControl(od.getControlId(), false));
        // 订单数据DTO Map  表格数据在子级控件中
        Map<Long, List<ApplicationOrderData>> orderDataMap = StreamUtil.groupK(orderDataList, ApplicationOrderData::getOrderId);
        return StreamUtil.transMapV_Expand(orderDataMap, (orderId, dataList) -> {
            ApplicationOrder applicationOrder = orderMap.get(orderId);
            // 处理数据
            Map<Long, Map<Long, List<ControlDataValueDTO>>> controlDataValuesMap = StreamUtil.groupFAndThenListToMap(
                    dataList,
                    notVoid,
                    ApplicationOrderData::getControlId,
                    list -> StreamUtil.toOrderlyMapCKV(
                            list,
                            Comparator.comparing(ApplicationOrderData::getSort),
                            ApplicationOrderData::getOrderDataId,
                            od -> dataConvert.initOrderDataValues(applicationOrder, od, perfect, filterCurrentNode)
                    )
            );

            // 订单控件map
            Map<Long, ControlDataDTO> orderControlMap = orderControlDataMap.get(orderId);
            // 订单子级控件map
            Map<Long, Map<Long, ControlDataDTO>> controlChildrenDataMap = orderControlChildrenDataMap.get(orderId);

            // 表格子字段列表
            List<Long> tableChildControlIds = new ArrayList<>();
            controlChildrenDataMap.forEach((id, map) -> {
                if (orderControlMap.containsKey(id)) {
                    if (ControlCodeEnum.TABLE.getCode().equals(orderControlMap.get(id).getControlCode())) {
                        tableChildControlIds.addAll(map.keySet());
                    }
                }
            });
            // 过滤 表格子字段 （递归中已处理，这里不需要重复处理）
            return StreamUtil.transListFT(orderControlMap.values(),
                    e -> !tableChildControlIds.contains(e.getControlId()),
                    e -> {
                        // 这里必须复制一份新的订单控件数据实体，否则会导致所有订单的数据都为最后一条单的
                        ControlDataDTO controlDataDTO = BeanUtil.copyProperties(e, ControlDataDTO.class);
                        // 递归处理 子级控件
                        this.recursionHandlerOrderData(controlDataDTO, controlDataValuesMap, controlChildrenDataMap);
                        return controlDataDTO;
                    });
        });
    }

    /**
     * 递归处理 子级控件
     *
     * @param controlData            当前控件
     * @param controlDataValuesMap   控件数据值map
     * @param controlChildrenDataMap 子级控件数据map
     */
    private void recursionHandlerOrderData(ControlDataDTO controlData,
                                           Map<Long, Map<Long, List<ControlDataValueDTO>>> controlDataValuesMap,
                                           Map<Long, Map<Long, ControlDataDTO>> controlChildrenDataMap) {
        // 控件值
        StreamUtil.isExistFirst(controlDataValuesMap.getOrDefault(controlData.getControlId(), new HashMap<>()).entrySet())
                .ifPresent(dataEntry -> {
                    controlData.setOrderDataId(dataEntry.getKey());
                    controlData.setValues(dataEntry.getValue());
                });

        // 表格 二维数据
        if (ControlCodeEnum.isTwoDimension(controlData.getControlCode())) {
            List<List<ControlDataDTO>> tableValues = new ArrayList<>();

            controlChildrenDataMap.getOrDefault(controlData.getControlId(), new HashMap<>()).forEach((controlId, data) -> {
                // 列数据
                List<ControlDataDTO> cellDataList = controlDataValuesMap.getOrDefault(controlId, new HashMap<>())
                        .entrySet().stream().map(dataEntry -> {
                            ControlDataDTO childControlData = BeanUtil.copyProperties(data, ControlDataDTO.class);
                            childControlData.setOrderDataId(dataEntry.getKey());
                            childControlData.setValues(dataEntry.getValue());

                            // 递归处理 子级控件
                            if (controlChildrenDataMap.containsKey(controlId)) {
                                this.recursionHandlerOrderData(childControlData, controlDataValuesMap, controlChildrenDataMap);
                            }
                            return childControlData;
                        })
                        .collect(Collectors.toList());

                // 列数据 分配到每一行
                for (int i = 0; i < cellDataList.size(); i++) {
                    if (tableValues.size() <= i) {
                        tableValues.add(new ArrayList<>());
                    }
                    List<ControlDataDTO> tableValue = tableValues.get(i);
                    tableValue.add(cellDataList.get(i));
                }
            });
            controlData.setTableValues(tableValues);
        }
    }

    /**
     * 节点控件控件转数据
     *
     * @param form       form
     * @param controlIds controlIds
     * @param controlMap controlMap
     * @return List
     */
    private List<ControlDataDTO> nodeControlToData(ApplicationForm form, Collection<Long> controlIds, Map<Long, ApplicationFormControl> controlMap) {
        List<ControlDataDTO> dataList = StreamUtil.transListFT(controlIds, controlMap::containsKey, e -> ApplicationUtil.controlToControlData(controlMap.get(e)));
        SpecialControlConfigDTO specialControlConfigDTO = ApplicationUtil.specialControlConfig(form.getSpecialControlConfig());
        return OrderSpecialControlEnum.supplySpecialControlData(specialControlConfigDTO, dataList);
    }

    /**
     * 订单数据转表单下拉项
     *
     * @param orderDataDTOList orderDataDTOList
     * @return FormOptionRespDTO
     */
    private List<FormOptionRespDTO> orderDataToFormOption(List<ApplicationOrderData> orderDataDTOList, DataConvert dataConvert) {
        return StreamUtil.transListT(orderDataDTOList, od -> this.orderDataToFormOption(od, dataConvert));
    }

    /**
     * 订单数据转表单下拉项
     *
     * @param orderData   orderData
     * @param dataConvert 订单数据转换 处理缓存
     * @return FormOptionRespDTO
     */
    private FormOptionRespDTO orderDataToFormOption(ApplicationOrderData orderData, DataConvert dataConvert) {
        // 数据控件类型
        ControlCodeEnum controlCodeEnum = dataConvert.getControlCodeByOrderData(orderData);
        // 初始化控件数据
        ControlDataDTO controlDataDTO = dataConvert.initOrderData(null, orderData, true, false);
        // 格式化值
        String value = controlCodeEnum.getControlDataToString().apply(controlDataDTO);

        OrderSelectOptionRespDTO formOptionRespDTO = new OrderSelectOptionRespDTO();
        // 关联选择 控件，选择的是orderDataId
        formOptionRespDTO.setOptionId(orderData.getOrderDataId());
        formOptionRespDTO.setParentOptionId(ApplicationUtil.DEFAULT_PARENT_OPTION_ID);
        formOptionRespDTO.setControlId(orderData.getControlId());
        formOptionRespDTO.setOptionValue(value);
        formOptionRespDTO.setOptionName(value);
        List<Long> controlValueIds = OrderDataUtil.getControlValueIds(controlDataDTO.getValues());
        if (controlCodeEnum.hasOptions()) {
            // 记录原选项id
            formOptionRespDTO.setSourceOptionIds(controlValueIds);
        } else if (controlCodeEnum.hasMemberSelect()) {
            formOptionRespDTO.setSourceMemIds(controlValueIds);
        }
        return formOptionRespDTO;
    }

    /**
     * 验证表单数据
     *
     * @param data       controlDataReqDTO
     * @param controlMap controlMap
     */
    private void verifyOrderData(ControlDataDTO oldData, ControlDataDTO data, ControlPermissionDTO controlPermission, Map<Long, ControlDTO> controlMap) {
        Long enterpriseId = loginUtil.getLoginEnterpriseId();
        List<ControlDataValueDTO> dateValues = data.getValues();
        // 检查新增权限
        if (!SwitchEnum.isOpen(controlPermission.getAddStatus())) {
            if (Objects.nonNull(oldData)) {
                if (Objects.isNull(oldData.getOrderDataId())) {
                    throw new BusinessException(RCodeEnum.ERROR_UNAUTHORIZED, this.getUnauthorizedMsg(data.getControlTitle(), "新增"));
                }
            }
        }
        // 检查编辑权限
        if (!SwitchEnum.isOpen(controlPermission.getModifyStatus())) {
            if (Objects.nonNull(oldData)) {
                if (OrderDataUtil.hasChangeValues(data, oldData)) {
                    throw new BusinessException(RCodeEnum.ERROR_UNAUTHORIZED, this.getUnauthorizedMsg(data.getControlTitle(), "编辑"));
                }
            }
        }
        // 检查控件
        if (!controlMap.containsKey(data.getControlId())) {
            throw new BusinessException(RCodeEnum.APPLICATION_FORM_CONTROL_NOT_EXIST);
        }
        ControlDTO controlDTO = controlMap.get(data.getControlId());
        data.setParentControlId(controlDTO.getParentControlId());
        data.setControlCode(controlDTO.getControlCode());

        // 检查不重复
        if (SwitchEnum.isOpen(controlDTO.getNoRepeat())) {
            if (elasticsearchService.isExistOrder(data)) {
                throw new BusinessException(BaseEnum.ERROR_PARAMETER,
                        String.format("控件[%s]不允许重复内容", controlDTO.getControlTitle()));
            }
        }

        ControlCodeEnum.findByCode(data.getControlCode());

        // 检查控件类型
        if (!data.getControlCode().equals(controlDTO.getControlCode())) {
            throw new BusinessException(BaseEnum.ERROR_PARAMETER, "控件code参数错误");
        }

        // 选择控件 需要校验选择项
        if (controlDTO instanceof SelectControlDTO selectControlDTO) {
            Set<Long> optionIds = ClassifyUtil.transTreeSetT(selectControlDTO.getOptions(), FormOptionRespDTO::getOptionId, FormOptionRespDTO::getChildrenOptions);
            if (!optionIds.containsAll(OrderDataUtil.getControlValueIds(dateValues))) {
                throw new BusinessException(BaseEnum.ERROR_PARAMETER,
                        String.format("控件[%s]下拉项id不存在", selectControlDTO.getControlTitle()));
            }
        }

        // 部门选择器 需要校验部门选择
        else if (controlDTO instanceof DeptSelControlDTO deptSelControlDTO) {
            ControlSelectConfigDTO memberSelectConfigDTO = deptSelControlDTO.getControlSelectConfig();

            Collection<Long> departmentIds = new HashSet<>();
            if (PermissionStatusEnum.ALL.getId() == memberSelectConfigDTO.getPermissionStatus()) {
                // 全体
                List<DepartmentBaseRespDTO> bases = remoteDepartmentService.bases(new DepartmentBasesReqDTO(enterpriseId));
                departmentIds.addAll(StreamUtil.transSetT(bases, DepartmentBaseRespDTO::getDepartmentId));
            } else {
                // 指定
                departmentIds.addAll(memberSelectConfigDTO.getScope().stream()
                        .filter(e -> ApplicationPermissionTypeEnum.DEPARTMENT.getId() == e.getPermissionType())
                        .map(AppPermissionDTO::getTargetId)
                        .toList());

            }
            if (dateValues.stream().anyMatch(e -> !departmentIds.contains(e.getId()))) {
                throw new BusinessException(BaseEnum.ERROR_PARAMETER,
                        String.format("控件[%s]下拉项id不存在", deptSelControlDTO.getControlTitle()));
            }
        }

        // 成员选择器 需要校验成员选择
        else if (controlDTO instanceof MemberSelControlDTO memberSelControlDTO) {
            ControlSelectConfigDTO memberSelectConfigDTO = memberSelControlDTO.getControlSelectConfig();

            Collection<Long> userIds = new HashSet<>();
            if (PermissionStatusEnum.ALL.getId() == memberSelectConfigDTO.getPermissionStatus()) {
                // 全体
                userIds.addAll(remoteUserEnterpriseService.enterpriseUserIds(FindUserIdsByIdReqDTO.filter(enterpriseId)));
            } else {
                // 指定
                userIds.addAll(applicationPermissionService.getPermissionUserIdsByAppPermissionDTO(null, memberSelectConfigDTO.getScope(), true));
            }
            if (dateValues.stream().anyMatch(e -> !userIds.contains(e.getId()))) {
                throw new BusinessException(BaseEnum.ERROR_PARAMETER,
                        String.format("控件[%s]下拉项id不存在", memberSelControlDTO.getControlTitle()));
            }
        }
    }

    /**
     * 初始化订单数据
     *
     * @param applicationOrder applicationOrder
     * @param dbOrderDataMap   dbOrderDataMap
     * @param controlData      controlData
     * @param sort             sort
     * @param ignoreOnlyChange 是否忽略仅变动才更新
     */
    private void initOrderData(List<ApplicationOrderData> modifies,
                               ApplicationOrder applicationOrder,
                               Map<Long, ApplicationOrderData> dbOrderDataMap,
                               ControlDataDTO controlData,
                               int sort,
                               boolean ignoreOnlyChange) {
        ApplicationOrderData applicationOrderData;
        boolean modify = false;
        if (Objects.nonNull(controlData.getOrderDataId()) && dbOrderDataMap.containsKey(controlData.getOrderDataId())) {
            applicationOrderData = dbOrderDataMap.get(controlData.getOrderDataId());
            modify = true;
        } else {
            applicationOrderData = this.createApplicationOrderData(applicationOrder.getOrderId(), controlData, sort);
        }
        List<ControlDataValueDTO> oldValues = JSON.parseArray(applicationOrderData.getOrderData(), ControlDataValueDTO.class);

        // 有变动、新增 才需要更新
        if (ignoreOnlyChange || !modify || OrderDataUtil.hasChangeValues(controlData.getControlCode(), controlData.getValues(), oldValues)) {
            // 该控件是否可以更新
            Boolean isCanUpdate = OrderSpecialControlEnum.isExistById(applicationOrderData.getControlId())
                    .map(OrderSpecialControlEnum::isCanUpdate)
                    .orElse(true);
            if (null == applicationOrderData.getOrderDataId() || isCanUpdate) {
                // 新控件数据/非特殊控件/可以修改的特殊控件参数
                applicationOrderData.setOrderData(JSON.toJSONString(controlData.getValues()));
                applicationOrderData.setSort(sort);

                modifies.add(applicationOrderData);
            }
        }
    }

    /**
     * 处理特殊控件数据
     *
     * @param applicationForm  applicationForm
     * @param applicationOrder applicationOrder
     * @param data             data
     * @param isCreate         isCreate
     */
    private void handleSpecial(ApplicationForm applicationForm, ApplicationOrder applicationOrder, Collection<ControlDataDTO> data, boolean isCreate) {
        DataConvert dataConvert = new DataConvert(loginUtil).initUserMap();
        SpecialControlConfigDTO specialControlConfigDTO = ApplicationUtil.specialControlConfig(applicationForm.getSpecialControlConfig());
        SpecialControlData specialControlData = BeanUtil.copyProperties(applicationOrder, SpecialControlData.class);
        if (isCreate) {
            // 补充所有特殊控件数据
            Set<Long> controlIds = StreamUtil.transSetT(data, ControlDataDTO::getControlId);
            OrderSpecialControlEnum.forEach(em -> {
                if (controlIds.contains(em.getId())) {
                    // 已存在
                    ControlDataDTO controlData = em.findControlData(data);
                    if (CollectionUtil.isEmpty(controlData.getValues())) {
                        controlData.setValues(em.getClassifier().apply(specialControlData, dataConvert::getUserBase));
                    }
                } else {
                    // 不存在
                    data.add(em.createControlData(specialControlConfigDTO, specialControlData, dataConvert::getUserBase));
                }
            });
        } else {
            // 补充特殊控件数据：更新时间
            OrderSpecialControlEnum.UPDATE.supplyData(specialControlConfigDTO, data, specialControlData, dataConvert::getUserBase);
            // 补充特殊控件数据：更新人
            OrderSpecialControlEnum.MODIFIER.supplyData(specialControlConfigDTO, data, specialControlData, dataConvert::getUserBase);
        }
        // 更新特殊控件数据：更新时间
        OrderSpecialControlEnum.UPDATE.modifyData(data, specialControlData, dataConvert::getUserBase);
        // 更新特殊控件数据：更新人
        OrderSpecialControlEnum.MODIFIER.modifyData(data, specialControlData, dataConvert::getUserBase);
    }

    /**
     * 创建订单数据
     *
     * @param orderId        orderId
     * @param controlDataDTO controlDataDTO
     * @return ApplicationOrderData
     */
    private ApplicationOrderData createApplicationOrderData(Long orderId, ControlDataDTO controlDataDTO, int sort) {
        ApplicationOrderData applicationOrderData = new ApplicationOrderData();
        applicationOrderData.setOrderId(orderId);
        applicationOrderData.setControlId(controlDataDTO.getControlId());
        applicationOrderData.setParentControlId(controlDataDTO.getParentControlId());
        applicationOrderData.setSort(sort);
        applicationOrderData.setIsDeleted(SwitchEnum.NO.getId());
        return applicationOrderData;
    }

    private String getUnauthorizedMsg(String title, String str) {
        return String.format("控件[%s]没有%s权限", title, str);
    }

    /**
     * 获取订单数据转换工具
     *
     * @return DataConvert
     */
    public DataConvert getDataConvert(Long enterpriseId, Long userId) {
        return new DataConvert(enterpriseId, userId)
                .initUserMap()
                .initDepartmentMap()
                .initNodeMap()
                .initFileMap()
                .initFormMap()
                .initControlMap()
                .initOptionMap()
                .initOrderMap()
                .initOrderQuoteMap()
                .initOrderNodeHandlerMap();
    }
}


